#!/usr/bin/env/ python
# -*- coding:utf-8 -*-

__author__ = 'shouke'



import time
import subprocess
import os
import  re

from log import logger


class MyAdb:
    '''adb工具命令封装'''

    def __init__(self):
        try:
            logger.info('正在获取adb.exe程序路径')
            curr_workdir = os.getcwd()
            self.adb_path = os.path.join(curr_workdir, 'adb\\adb.exe') # 注意，这里不能使用 adb/adb.exe，否则执行命令使用管道时 xxx | findstr "cpu"，提示 adb不是内部或外部命令,也不是可运行的程序或批处理
            self.timeout = 30 # 超时时间
        except Exception as e:
            logger.error('程序adb初始化操作失败：%s' % e)
            exit()

    def kill_server(self):
        '''使用adb kill-server停止adb服务'''

        with subprocess.Popen(self.adb_path + ' kill-server', stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, universal_newlines=True) as proc:
            try:
                outs, errs = proc.communicate(timeout=self.timeout)
                if proc.returncode:
                    logger.error('停止adb服务失败：%s' % errs)
                    result = False
                elif outs == '' or outs.find('server not running') != -1:
                    logger.info('停止adb服务成功 %s' % outs)
                    time.sleep(1)
                    result = True
                else:
                    logger.error('停止adb服务失败：%s' % errs)
                    result = False
            except Exception as e:
                proc.kill()
                logger.error('停止adb服务失败：%s' % e)
                result = False
        return result

    def start_server(self):
        '''使用adb start-server启动adb服务'''

        with subprocess.Popen(self.adb_path + ' start-server', stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, universal_newlines=True) as proc:
            try:
                outs, errs = proc.communicate(timeout=self.timeout)
                if proc.returncode:
                    logger.error('启动adb服务失败：%s' % errs)
                    result = False
                elif outs == '' or outs.find('daemon started successfully') != -1:
                    logger.info('启动adb服务成功：%s' % outs)
                    time.sleep(1)
                    result = True
                else:
                    logger.error('启动adb服务失败：%s' % errs)
                    result = False
            except Exception as e:
                proc.kill()
                logger.error('启动adb服务失败：%s' % e)
                result = False
        return result


    def connect_device(self, ip, port):
        '''使用adb connect device_ip:port 命令通过wifi下连接ip'''

        with subprocess.Popen(self.adb_path + ' connect %s:%s' % (ip, port), stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, universal_newlines=True) as proc:
            try:
                outs, errs = proc.communicate(timeout=self.timeout)
                if proc.returncode:
                    logger.error('设备%s:%s连接失败：%s' % (ip, port, errs))
                    result = False
                elif outs.find('already connected to %s:%s' % (ip, port)) != -1:
                    logger.info('设备%s:%s连接成功：%s' % (ip, port, outs))
                    result = True
                else:
                    logger.error('设备%s:%s连接失败：%s' % (ip, port, errs))
                    result = False
            except Exception as e:
                proc.kill()
                logger.error('设备(%s:%s))连接失败：%s' % (ip, port, e))
                result = False
        return result

    def get_devices(self):
        '''使用adb devices -l 命令获取所有设备列表'''

        device_list = [] # 存放设备列表信息
        with subprocess.Popen(self.adb_path + ' devices -l', stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, universal_newlines=True) as proc:
            try:
                outs, errs = proc.communicate(timeout=self.timeout)
                if proc.returncode:
                    logger.error('获取设备列表失败：%s' % errs)
                else:
                    # logger.info('获取设备列表输出：%s' % outs)
                    result = re.findall('([^\n]+?)\s+(\w+)\s+product:(.+?)\s+model:(.+?)\s+device:(.+?)\n', outs) # 正则表达式获取设备列表[[设备标识, 设备状态, product, model,device],[……]]
                    device_list = [list(item) for item in result if item[1] == 'device']
            except Exception as e:
                proc.kill()
                logger.error('获取设备列表失败：%s' % e)
        return device_list

    def get_packages(self, serial_number):
        '''使用adb -s SN shell pm list packages 命令获取所有应用包列表'''

        package_list = [] # 存放设备列表信息
        with subprocess.Popen(self.adb_path + ' -s %s shell pm list packages' % serial_number, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, universal_newlines=True) as proc:
            try:
                outs, errs = proc.communicate(timeout=self.timeout)
                if proc.returncode:
                    logger.error('获取有应用包列表失败：%s' % errs)
                else:
                    logger.info('获取有应用包列表成功：%s' % outs)
                    package_list = re.findall('package:([^\n]+?)\n', outs)
            except Exception as e:
                proc.kill()
                logger.error('获取有应用包列表失败：%s' % e)
        return package_list


    def get_cpu_data(self, serial_number):
        '''
        使用adb -s SN shell "cat /proc/stat | grep 'cpu '"命令获取整体cpu使用信息
        注意，命令必须采用双引号包围，否则会执行出错，提示 'grep' 不是内部或外部命令，也不是可运行的程序或批处理文件。
        '''
        sample_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()) # 记录采样时间

        with subprocess.Popen(self.adb_path + ' -s %s shell "cat /proc/stat | grep \'cpu \'"' % serial_number , stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, universal_newlines=True) as proc:
            try:
                outs, errs = proc.communicate(timeout=self.timeout)
                if proc.returncode:
                    logger.error('获取设备%s整体cpu快照信息失败：%s' % (serial_number, errs))
                    result = [False, '%s' % errs]
                elif outs.find('cpu') != -1:
                    temp_dict = {}
                    temp_dict['sample_time'] = sample_time # 采样时间
                    temp_dict['data'] = outs # 采样数据
                    result= [True, temp_dict]
                else:
                    logger.error('获取设备%s整体cpu快照信息失败：%s' % (serial_number, errs))
                    result = [False, '%s' % errs]
            except Exception as e:
                proc.kill()
                logger.error('获取设备%s整体cpu快照信息失败：%s' % (serial_number, e))
                result = [False, '%s' % e]
        return result



    def get_package_pid(self, serial_number, package_name):
        '''使用adb -s SN shell "ps | grep package_name"命令获取应用包对应的进程ID'''

        with subprocess.Popen(self.adb_path + ' -s %s shell "ps | grep %s"' % (serial_number, package_name) , stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, universal_newlines=True) as proc:
            try:
                outs, errs = proc.communicate(timeout=self.timeout)
                if proc.returncode:
                    logger.error('获取设备%s 应用包%s 进程ID失败：%s' % (serial_number, package_name, errs))
                    result = [False, '%s' % errs]
                elif outs.find(package_name) != -1 :
                    pid = re.findall('.+?\s+(\d+)\s', outs)[0]
                    # logger.info('获取设备%s %s应用包进程ID成功,PID：%s' %  (serial_number, package_name, pid))
                    result = [True, pid]
                else:
                    logger.error('获取设备%s 应用包%s 进程ID失败：%s' % (serial_number, package_name, errs))
                    result= [False, '%s' % errs]
            except Exception as e:
                proc.kill()
                logger.error('获取设备%s 应用包%s 进程ID失败：%s' % (serial_number, package_name, e))
                result = [False, '%s' % e]
        return result


    def get_proc_cpu_data(self, serial_number, pid, package_name):
        '''
        使用adb -s SN shell cat /proc/<pid>/stat 命令获取单个进程cpu使用信息
        '''

        sample_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()) # 记录采样时间
        with subprocess.Popen(self.adb_path + ' -s %s shell "cat /proc/%s/stat && cat /proc/stat | grep \'cpu \' "' % (serial_number, pid) , stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, universal_newlines=True) as proc:
            try:
                outs, errs = proc.communicate(timeout=self.timeout)
                if proc.returncode:
                    logger.error('获取设备%s 应用包%s 进程(pid：%s)cpu快照信息失败：%s' % (serial_number, package_name, pid,  errs))
                    result = [False, '%s' % errs]
                elif outs[:4] == pid:
                    # logger.info('获取设备%s %s应用包进程(pid:%s)cpu快照信息成功：%s' % (serial_number, package_name, pid, outs))
                    temp_dict = {}
                    temp_dict['sample_time'] = sample_time # 采样时间
                    temp_dict['data'] = outs # 采样数据
                    result = [True, temp_dict]
                else:
                    logger.error('获取设备%s 应用包%s 进程(pid:%s)cpu快照信息失败：%s' % (serial_number, package_name, pid, errs))
                    result= [False, '%s' % errs]
            except Exception as e:
                proc.kill()
                logger.error('获取设备%s 应用包%s 进程(pid:%s)cpu快照信息失败：%s' % (serial_number, package_name, pid, e))
                result = [False, '%s' % e]
        return result


    def get_mem_data(self, serial_number):
        '''使用adb -s SN shell free 命令获取系统内存使用信息'''

        sample_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()) # 记录采样时间
        with subprocess.Popen(self.adb_path + ' -s %s shell free' % serial_number , stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, universal_newlines=True) as proc:
            try:
                outs, errs = proc.communicate(timeout=self.timeout)
                if proc.returncode:
                    logger.error('获取设备%s内存信息失败：%s' % (serial_number, errs))
                    result = [False, '%s' % errs]
                elif outs.find('free') != -1:
                    # logger.info('获取设备%s内存信息成功：%s' % (serial_number, outs))
                    temp_dict = {}
                    temp_dict['sample_time'] = sample_time # 采样时间
                    temp_dict['data'] = outs # 采样数据
                    result= [True, temp_dict]
                else:
                    logger.error('获取设备%s内存信息失败：%s' % (serial_number, errs))
                    result = [False, '%s' % errs]
            except Exception as e:
                proc.kill()
                logger.error('获取设备%s内存信息失败：%s' % (serial_number, e))
                result = [False, '%s' % e]
        return result


    def get_proc_mem_data(self, serial_number, pid, package_name):
        '''使用adb -s SN shell "cat /proc/<pid>/status | grep -E 'VmRSS|VmSize|VmData|VmStk|VmExe|VmLib'"   命令获取单个进程内存使用信息
        VmRSS：进程使用的物理内存
        VmSwap：进程占用swap大小
        VmPeak：进程运行过程中占用内存的峰值
        '''

        sample_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()) # 记录采样时间
        with subprocess.Popen(self.adb_path + ' -s %s shell "cat /proc/%s/status | grep -E \'VmRSS|VmSize|VmData|VmStk|VmExe|VmLib\'"' % (serial_number, pid) , stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, universal_newlines=True) as proc:
            try:
                outs, errs = proc.communicate(timeout=self.timeout)
                if proc.returncode:
                    logger.error('获取设备%s 应用包%s 进程(pid：%s)内存信息失败：%s' % (serial_number, package_name, pid,  errs))
                    result = [False, '%s' % errs]
                elif outs.find('VmRSS') != -1:
                    # logger.info('获取设备%s %s应用包进程(pid:%s)内存信息成功：%s' % (serial_number, package_name, pid, outs))
                    temp_dict = {}
                    temp_dict['sample_time'] = sample_time # 采样时间
                    temp_dict['data'] = outs # 采样数据
                    result= [True, temp_dict]
                else:
                    logger.error('获取设备%s 应用包%s 进程(pid：%s)内存信息失败：%s' % (serial_number, package_name, pid,  errs))
                    result = [False, '%s' % errs]
            except Exception as e:
                proc.kill()
                logger.error('获取设备%s s应用包%s 进程(pid:%s)内存信息失败：%s' % (serial_number, package_name, pid, e))
                result = [False, '%s' % e]
        return result


    def get_battery_data(self, serial_number):
        '''使用adb -s SN shell dumpsys battery   命令获取电量信息'''

        sample_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()) # 记录采样时间
        with subprocess.Popen(self.adb_path + ' -s %s shell dumpsys battery' % serial_number, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, universal_newlines=True) as proc:
            try:
                outs, errs = proc.communicate(timeout=self.timeout)
                if proc.returncode:
                    logger.error('获取设备%s电量信息失败：%s' % (serial_number, errs))
                    result = [False, '%s' % errs]
                elif outs.find('USB powered') != -1:
                    # logger.info('获取设备%s电量信息成功：%s' % (serial_number, outs))
                    temp_dict = {}
                    temp_dict['sample_time'] = sample_time # 采样时间
                    temp_dict['data'] = outs # 采样数据
                    result= [True, temp_dict]
                else:
                    logger.error('获取设备%s电量信息失败：%s' % (serial_number, errs))
                    result = [False,  '%s' % errs]
            except Exception as e:
                proc.kill()
                logger.error('获取设备%s电量信息失败：%s' % (serial_number, e))
                result = [False, '%s' % e]
        return result


    def get_net_dev_flow_data(self, serial_number):
        '''使用adb -s SN shell "cat /proc/net/dev | grep -v lo"  命令获取设备网卡流量信息'''

        sample_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()) # 记录采样时间
        with subprocess.Popen(self.adb_path + ' -s %s shell "cat /proc/net/dev | grep -v lo"' % serial_number, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, universal_newlines=True) as proc:
            try:
                outs, errs = proc.communicate(timeout=self.timeout)
                if proc.returncode:
                    logger.error('获取设备%s 网卡设备流量信息失败：%s' % (serial_number,  errs))
                    result = [False,  '%s' % errs]
                elif outs.find('Receive ') != -1 and outs.find('Transmit') != -1:
                    # logger.info('获取设备%s %s应用程序包帧率信息成功：%s' % (serial_number, package_name, outs))
                    temp_dict = {}
                    temp_dict['sample_time'] = sample_time # 采样时间
                    temp_dict['data'] = outs # 采样数据
                    result= [True, temp_dict]
                else:
                    logger.error('获取设备%s 网卡设备流量信息失败：%s' % (serial_number,  errs))
                    result = [False,  '%s' % errs]
            except Exception as e:
                proc.kill()
                logger.error('获取设备%s 网卡设备流量信息失败：%s' % (serial_number, e))
                result = [False, '%s' % errs]
        return result


    def get_proc_net_dev_flow_data(self, serial_number, pid, package_name):
        '''使用adb -s SN shell "cat /proc/<pid>/net/dev | grep -v lo"  命令获取进程网卡流量信息'''

        sample_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()) # 记录采样时间
        with subprocess.Popen(self.adb_path + ' -s %s shell "cat /proc/%s/net/dev | grep -v lo"' % (serial_number, pid), stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, universal_newlines=True) as proc:
            try:
                outs, errs = proc.communicate(timeout=self.timeout)
                if proc.returncode:
                    logger.error('获取设备%s 应用程序包%s 的网卡设备流量信息失败：%s' % (serial_number, package_name, errs))
                    result = [False, '%s' % errs]
                elif outs.find('Receive ') != -1 and outs.find('Transmit') != -1:
                    # logger.info('获取设备%s %s应用程序包帧率信息成功：%s' % (serial_number, package_name, outs))
                    temp_dict = {}
                    temp_dict['sample_time'] = sample_time # 采样时间
                    temp_dict['data'] = outs # 采样数据
                    result= [True, temp_dict]
                else:
                    logger.error('获取设备%s 应用程序包%s 的网卡流量信息失败：%s' % (serial_number, package_name, errs))
                    result = [False,  '%s' % errs]
            except Exception as e:
                proc.kill()
                logger.error('获取设备%s 应用程序包%s 的网卡设备流量信息失败：%s' % (serial_number, package_name, e))
                result = [False, '%s' % e]
        return result


    def get_gfx_data(self, serial_number, package_name):
        '''使用adb -s SN shell dumpsys gfxinfo package_name  命令获取帧率信息'''

        sample_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()) # 记录采样时间
        with subprocess.Popen(self.adb_path + ' -s %s shell dumpsys gfxinfo %s' % (serial_number, package_name), stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, universal_newlines=True) as proc:
            try:
                outs, errs = proc.communicate(timeout=self.timeout)
                if proc.returncode:
                    logger.error('获取设备%s 应用程序包%s 的帧率信息失败：%s' % (serial_number, package_name, errs))
                    result = [False,  '%s' % errs]
                elif outs.find('Graphics info for pid ') != -1 and outs.find('Total Views') != -1:
                    # logger.info('获取设备%s %s应用程序包帧率信息成功：%s' % (serial_number, package_name, outs))
                    temp_dict = {}
                    temp_dict['sample_time'] = sample_time # 采样时间
                    temp_dict['data'] = outs # 采样数据
                    result= [True, temp_dict]
                else:
                    logger.error('获取设备%s 应用程序包%s 的帧率信息失败：%s' % (serial_number, package_name, errs))
                    result = [False, '%s' % errs]
            except Exception as e:
                proc.kill()
                logger.error('获取设备%s 应用程序包%s 的帧率信息失败：%s' % (serial_number, package_name, e))
                result = [False, '%s' % e]
        return result


    def get_cpu_processor_num(self, serial_number):
        '''使用adb -s SN shell "cat /proc/cpuinfo | grep processor | wc -l" 命令获取系统逻辑cpu数'''

        sample_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()) # 记录采样时间
        with subprocess.Popen(self.adb_path + ' -s %s shell "cat /proc/cpuinfo | grep processor | wc -l"' % serial_number , stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, universal_newlines=True) as proc:
            try:
                outs, errs = proc.communicate(timeout=self.timeout)
                outs = outs.strip()
                if proc.returncode:
                    logger.error('获取设备%s系统逻辑CPU数失败：%s' % (serial_number, errs))
                    result = [False, '%s' % errs]
                elif outs.isdigit():
                    result= [True, outs]
                else:
                    logger.error('获取设备%s系统逻辑CPU数失败：%s' % (serial_number, errs))
                    result = [False, '%s' % errs]
            except Exception as e:
                proc.kill()
                logger.error('获取设备%s系统逻辑CPU数失败：%s' % (serial_number,  e))
                result = [False, '%s' % e]
        return result